package com.wzb.mybatisplus.bitaction.electrumaction;

import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.*;
import org.bitcoinj.core.*;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.script.Script;
import org.bitcoinj.wallet.DeterministicSeed;
import org.bitcoinj.wallet.Wallet;

import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.TimeUnit;

public class ElectrumPrivateKeyDemo {

    private static final ObjectMapper mapper = new ObjectMapper();
    private static final OkHttpClient httpClient = new OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .build();

    private static final NetworkParameters params = MainNetParams.get();
    private String currentServer;

    public static void main(String[] args) {
        System.out.println("=== Electrum 私钥查询工具 ===");

//        if (args.length == 0) {
//            System.out.println("用法: java ElectrumPrivateKeyDemo <私钥>");
//            System.out.println("私钥格式: WIF格式或16进制");
//            System.out.println("示例: java ElectrumPrivateKeyDemo 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79ZKvY");
//            return;
//        }

        String privateKey = "5Kb8kLf9zgWQnogidDA76MzPL6TsZZY36hWXMssSzNydYXYB9KF";
        ElectrumPrivateKeyDemo client = new ElectrumPrivateKeyDemo();

        try {
            client.run(privateKey);
        } catch (Exception e) {
            System.err.println("❌ 执行失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    public void run(String privateKey) throws Exception {
        // 1. 连接服务器
        connectToServer();

        // 2. 从私钥推导地址
        System.out.println("\n🔑 私钥信息:");
        ECKey ecKey = importPrivateKey(privateKey);
        List<String> addresses = deriveAddresses(ecKey);

        // 3. 查询每个地址的信息
        System.out.println("\n📊 地址余额和交易:");
        for (String address : addresses) {
            queryAddressInfo(address);
        }

        // 4. 汇总信息
        System.out.println("\n📈 汇总信息:");
        displaySummary(addresses);
    }

    /**
     * 连接到Electrum服务器
     */
    private void connectToServer() throws Exception {
        String[] servers = {
                "https://electrumx.bitcoins.sk:50002",
                "https://electrum.emzy.de:50002",
                "https://electrum.qtornado.com:50002",
                "https://electrum.bauerj.eu:50002"
        };

        for (String server : servers) {
            try {
                System.out.println("尝试连接: " + server);

                Map<String, Object> request = createRequest("server.ping", new Object[]{});
                String response = sendRequest(server, request);

                if (response != null) {
                    this.currentServer = server;
                    System.out.println("✓ 成功连接到: " + server);

                    // 显示服务器信息
                    displayServerInfo();
                    return;
                }
            } catch (Exception e) {
                System.out.println("✗ 连接失败: " + server + " - " + e.getMessage());
            }
        }

        throw new RuntimeException("无法连接到任何Electrum服务器");
    }

    /**
     * 导入私钥
     */
    private ECKey importPrivateKey(String privateKeyStr) throws Exception {
        String cleanKey = privateKeyStr.trim();

        try {
            ECKey ecKey;

            // 尝试作为WIF格式导入
            if (cleanKey.length() == 51 || cleanKey.length() == 52) {
                DumpedPrivateKey dumpedPrivateKey = DumpedPrivateKey.fromBase58(params, cleanKey);
                ecKey = dumpedPrivateKey.getKey();
                System.out.println("✓ 私钥格式: WIF");
            }
            // 尝试作为16进制格式导入
            else if (cleanKey.length() == 64) {
                BigInteger privKey = new BigInteger(cleanKey, 16);
                ecKey = ECKey.fromPrivate(privKey);
                System.out.println("✓ 私钥格式: 16进制");
            }
            else {
                throw new IllegalArgumentException("不支持的私钥格式");
            }

            // 显示私钥信息
            System.out.println("✓ 私钥导入成功");
            System.out.println("  公钥: " + Utils.HEX.encode(ecKey.getPubKey()));
            System.out.println("  压缩公钥: " + Utils.HEX.encode(ecKey.getPubKeyPoint().getEncoded(true)));

            return ecKey;

        } catch (Exception e) {
            throw new RuntimeException("私钥导入失败: " + e.getMessage());
        }
    }

    /**
     * 从私钥推导各种地址类型
     */
    private List<String> deriveAddresses(ECKey ecKey) {
        List<String> addresses = new ArrayList<>();

        System.out.println("\n📍 推导地址:");

        try {
            // 1. P2PKH (传统地址) - 1开头
            LegacyAddress p2pkhAddress = LegacyAddress.fromKey(params, ecKey);
            addresses.add(p2pkhAddress.toString());
            System.out.println("✓ P2PKH地址: " + p2pkhAddress.toString());

            // 2. P2WPKH (原生隔离见证) - bc1开头
            SegwitAddress p2wpkhAddress = SegwitAddress.fromKey(params, ecKey);
            addresses.add(p2wpkhAddress.toString());
            System.out.println("✓ P2WPKH地址: " + p2wpkhAddress.toString());

            // 3. P2SH-P2WPKH (兼容隔离见证) - 3开头
            SegwitAddress segwit = SegwitAddress.fromKey(params, ecKey);
            LegacyAddress p2shAddress = LegacyAddress.fromScriptHash(params,
                    segwit.getHash());
            addresses.add(p2shAddress.toString());
            System.out.println("✓ P2SH-P2WPKH地址: " + p2shAddress.toString());

        } catch (Exception e) {
            System.err.println("地址推导失败: " + e.getMessage());
        }

        return addresses;
    }

    /**
     * 查询地址信息
     */
    private void queryAddressInfo(String address) throws Exception {
        System.out.println("\n🔍 查询地址: " + address);

        // 获取余额
        Map<String, Object> balanceReq = createRequest("blockchain.address.get_balance",
                new Object[]{address});
        String balanceJson = sendRequest(currentServer, balanceReq);
        displayBalance(balanceJson, address);

        // 获取交易历史
        Map<String, Object> historyReq = createRequest("blockchain.address.get_history",
                new Object[]{address});
        String historyJson = sendRequest(currentServer, historyReq);
        displayTransactionHistory(historyJson, address);

        // 获取UTXOs
        Map<String, Object> utxoReq = createRequest("blockchain.address.listunspent",
                new Object[]{address});
        String utxoJson = sendRequest(currentServer, utxoReq);
        displayUtxos(utxoJson, address);
    }

    /**
     * 显示余额信息
     */
    private void displayBalance(String balanceJson, String address) throws Exception {
        Map<String, Object> balance = mapper.readValue(balanceJson, Map.class);
        long confirmed = ((Number) balance.get("confirmed")).longValue();
        long unconfirmed = ((Number) balance.get("unconfirmed")).longValue();

        double confirmedBtc = confirmed / 100_000_000.0;
        double unconfirmedBtc = unconfirmed / 100_000_000.0;

        System.out.println("💰 余额信息:");
        System.out.println("  确认余额: " + confirmed + " satoshis (" + confirmedBtc + " BTC)");
        System.out.println("  未确认余额: " + unconfirmed + " satoshis (" + unconfirmedBtc + " BTC)");
        System.out.println("  总余额: " + (confirmed + unconfirmed) + " satoshis (" +
                (confirmedBtc + unconfirmedBtc) + " BTC)");
    }

    /**
     * 显示交易历史
     */
    @SuppressWarnings("unchecked")
    private void displayTransactionHistory(String historyJson, String address) throws Exception {
        List<Map<String, Object>> history = mapper.readValue(historyJson, List.class);

        System.out.println("📜 交易历史 (" + history.size() + " 笔交易):");

        for (int i = 0; i < Math.min(5, history.size()); i++) {
            Map<String, Object> tx = history.get(i);
            String txHash = (String) tx.get("tx_hash");
            Integer height = (Integer) tx.get("height");

            // 获取交易详情
            Map<String, Object> txReq = createRequest("blockchain.transaction.get",
                    new Object[]{txHash, true});
            String txJson = sendRequest(currentServer, txReq);

            if (txJson != null) {
                Map<String, Object> txDetail = mapper.readValue(txJson, Map.class);
                displayTransactionSummary(txDetail, address, i + 1);
            }
        }

        if (history.size() > 5) {
            System.out.println("  ... 还有 " + (history.size() - 5) + " 笔交易未显示");
        }
    }

    /**
     * 显示交易摘要
     */
    @SuppressWarnings("unchecked")
    private void displayTransactionSummary(Map<String, Object> tx, String address, int index) {
        String txId = (String) tx.get("txid");
        Integer confirmations = (Integer) tx.get("confirmations");
        Long time = (Long) tx.get("time");
        List<Map<String, Object>> vout = (List<Map<String, Object>>) tx.get("vout");

        // 计算该地址在交易中的金额
        long amount = 0;
        for (Map<String, Object> output : vout) {
            Map<String, Object> scriptPubKey = (Map<String, Object>) output.get("scriptPubKey");
            if (scriptPubKey != null && scriptPubKey.containsKey("addresses")) {
                List<String> addresses = (List<String>) scriptPubKey.get("addresses");
                if (addresses.contains(address)) {
                    amount += ((Number) output.get("value")).longValue();
                }
            }
        }

        System.out.println("  " + index + ". " + shortenHash(txId) +
                " | 金额: " + amount + " sats" +
                " | 确认数: " + (confirmations != null ? confirmations : 0) +
                " | 时间: " + (time != null ? new Date(time * 1000) : "未知"));
    }

    /**
     * 显示UTXOs
     */
    @SuppressWarnings("unchecked")
    private void displayUtxos(String utxoJson, String address) throws Exception {
        List<Map<String, Object>> utxos = mapper.readValue(utxoJson, List.class);

        System.out.println("💎 UTXOs (" + utxos.size() + " 个未花费输出):");

        long totalValue = 0;
        for (Map<String, Object> utxo : utxos) {
            String txHash = (String) utxo.get("tx_hash");
            int txPos = ((Number) utxo.get("tx_pos")).intValue();
            long value = ((Number) utxo.get("value")).longValue();
            int height = ((Number) utxo.get("height")).intValue();

            totalValue += value;

            System.out.println("  - " + shortenHash(txHash) + ":" + txPos +
                    " | 金额: " + value + " sats" +
                    " | 高度: " + height);
        }

        if (utxos.size() > 0) {
            System.out.println("  总UTXO金额: " + totalValue + " sats (" +
                    (totalValue / 100_000_000.0) + " BTC)");
        }
    }

    /**
     * 显示服务器信息
     */
    private void displayServerInfo() throws Exception {
        Map<String, Object> versionReq = createRequest("server.version",
                new Object[]{"java-private-key-client", "1.4"});
        String version = sendRequest(currentServer, versionReq);

        Map<String, Object> heightReq = createRequest("blockchain.headers.subscribe", new Object[]{});
        String heightInfo = sendRequest(currentServer, heightReq);

        System.out.println("📡 服务器信息:");
        System.out.println("  版本: " + version);
        System.out.println("  区块信息: " + heightInfo);
    }

    /**
     * 显示汇总信息
     */
    private void displaySummary(List<String> addresses) throws Exception {
        long totalBalance = 0;
        int totalTransactions = 0;
        long totalUtxoValue = 0;
        int totalUtxos = 0;

        for (String address : addresses) {
            // 余额
            Map<String, Object> balanceReq = createRequest("blockchain.address.get_balance",
                    new Object[]{address});
            String balanceJson = sendRequest(currentServer, balanceReq);
            Map<String, Object> balance = mapper.readValue(balanceJson, Map.class);
            totalBalance += ((Number) balance.get("confirmed")).longValue();
            totalBalance += ((Number) balance.get("unconfirmed")).longValue();

            // 交易数
            Map<String, Object> historyReq = createRequest("blockchain.address.get_history",
                    new Object[]{address});
            String historyJson = sendRequest(currentServer, historyReq);
            List<?> history = mapper.readValue(historyJson, List.class);
            totalTransactions += history.size();

            // UTXOs
            Map<String, Object> utxoReq = createRequest("blockchain.address.listunspent",
                    new Object[]{address});
            String utxoJson = sendRequest(currentServer, utxoReq);
            List<Map<String, Object>> utxos = mapper.readValue(utxoJson, List.class);
            totalUtxos += utxos.size();

            for (Map<String, Object> utxo : utxos) {
                totalUtxoValue += ((Number) utxo.get("value")).longValue();
            }
        }

        System.out.println("🎯 钱包汇总:");
        System.out.println("  总余额: " + totalBalance + " sats (" +
                (totalBalance / 100_000_000.0) + " BTC)");
        System.out.println("  总交易数: " + totalTransactions);
        System.out.println("  总UTXO数: " + totalUtxos);
        System.out.println("  UTXO总金额: " + totalUtxoValue + " sats");
        System.out.println("  监控地址数: " + addresses.size());
    }

    // ========== 工具方法 ==========

    private String sendRequest(String url, Map<String, Object> request) throws Exception {
        String requestBody = mapper.writeValueAsString(request);

        Request httpRequest = new Request.Builder()
                .url(url)
                .post(RequestBody.create(requestBody, MediaType.parse("application/json")))
                .addHeader("Content-Type", "application/json")
                .build();

        try (Response response = httpClient.newCall(httpRequest).execute()) {
            if (!response.isSuccessful()) {
                throw new RuntimeException("HTTP错误: " + response.code());
            }

            String responseBody = response.body().string();
            Map<String, Object> jsonResponse = mapper.readValue(responseBody, Map.class);

            if (jsonResponse.containsKey("error") && jsonResponse.get("error") != null) {
                throw new RuntimeException("RPC错误: " + jsonResponse.get("error"));
            }

            return mapper.writeValueAsString(jsonResponse.get("result"));
        }
    }

    private Map<String, Object> createRequest(String method, Object[] params) {
        Map<String, Object> request = new HashMap<>();
        request.put("jsonrpc", "2.0");
        request.put("id", UUID.randomUUID().toString());
        request.put("method", method);
        request.put("params", params);
        return request;
    }

    private String shortenHash(String hash) {
        if (hash == null || hash.length() < 16) return hash;
        return hash.substring(0, 8) + "..." + hash.substring(hash.length() - 8);
    }
}